//
//  UIImage+AD.swift
//  ADKit
//
//  Created by Adoma on 2020/10/22.
//

import UIKit
import Photos
import ImageIO

public extension UIImage {
    
    /// by ADKit
    convenience init?(color: UIColor) {
        let rect = CGRect.init(x: 0, y: 0, width: 1, height: 1)
        let render = UIGraphicsImageRenderer(size: rect.size)
        let data = render.pngData { context in
            color.setFill()
            context.fill(rect)
        }
        self.init(data: data)
    }

}

public extension UIImage {
    
    func alwaysOriginal() -> UIImage {
        return self.withRenderingMode(.alwaysOriginal)
    }
    
    func alwaysTemplate() -> UIImage {
        return self.withRenderingMode(.alwaysTemplate)
    }
    
    func savetoAlbum(_ completionHandler: ((Bool, Error?) -> Void)? = nil) {
        PHPhotoLibrary.requestAuthorization { (status) in
            switch status {
            case .authorized:
                PHPhotoLibrary.shared().performChanges({
                    PHAssetChangeRequest.creationRequestForAsset(from: self)
                }, completionHandler: completionHandler)
            default:
                completionHandler?(false, ADError.notAuthorization)
            }
        }
    }
    
    convenience init?(name: String, bundle: Bundle = .main) {
        self.init(named: name, in: bundle, compatibleWith: nil)
    }
    
}

public extension UIImage {
    
    class func screenshot() -> UIImage? {

        guard let window = WindowManager.keyWindow else { return nil }
        
        let rect = UIScreen.main.bounds

        let render = UIGraphicsImageRenderer(size: rect.size)
        
        let image = render.image { context in
            
            window.drawHierarchy(in: rect, afterScreenUpdates: true)

        }
        
        return image
    }
}

public extension UIImage {
    
    func compress(to count: Int) -> Data? {
        
        guard let pngImageData = pngData() else {
            return nil
        }
                
        if pngImageData.count <= count {
            return pngImageData
        }
        
        var compressionQuality: CGFloat = 1
        var jpegImageData: Data!
        
        repeat {
            guard let data = jpegData(compressionQuality: compressionQuality) else { return nil }
            compressionQuality -= 0.1
            jpegImageData = data
        } while jpegImageData.count > count && compressionQuality > 0
 
        guard jpegImageData.count <= count else {
            return nil
        }
        
        return jpegImageData
    }
    
}

public extension Data {
    
    func compressGIF(with scale: CGFloat) -> Data? {
        
        guard let source = CGImageSourceCreateWithData(self as CFData, nil),
              let type = CGImageSourceGetType(source) else {
            return nil
        }

        let count = CGImageSourceGetCount(source)
        let options: [CFString: Any] = [
            kCGImageDestinationLossyCompressionQuality: scale
        ]

        let outputData = NSMutableData()
        guard let destination = CGImageDestinationCreateWithData(outputData, type, count, nil) else {
            return nil
        }

        for i in 0..<count {
            if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
                CGImageDestinationAddImage(destination, image, options as CFDictionary)
            }
        }

        if CGImageDestinationFinalize(destination) {
            return outputData as Data
        } else {
            return nil
        }
    }

    func resizeGIF(to targetSize: CGSize) -> Data? {
        
        guard let source = CGImageSourceCreateWithData(self as CFData, nil),
              let type = CGImageSourceGetType(source) else {
            return nil
        }

        let count = CGImageSourceGetCount(source)
        let outputData = NSMutableData()
        guard let destination = CGImageDestinationCreateWithData(outputData, type, count, nil) else {
            return nil
        }

        for i in 0..<count {
            if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
                
                let format = UIGraphicsImageRendererFormat()
                format.scale = 1
                let renderer = UIGraphicsImageRenderer(size: targetSize, format: format)
                let resizedImage = renderer.image { _ in
                    UIImage(cgImage: image).draw(in: CGRect(origin: .zero, size: targetSize))
                }
                
                if let resizedCGImage = resizedImage.cgImage {
                    CGImageDestinationAddImage(destination, resizedCGImage, nil)
                }
            }
        }

        if CGImageDestinationFinalize(destination) {
            return outputData as Data
        } else {
            return nil
        }
    }
}
